﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Linq;
using System.Collections.Specialized;

namespace Gmantis.Controls
{
    public class LinePanel : Panel
    {
        // Fields
        private ObservableCollection<LineDefinition> _lineDefinitions;
        public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(LinePanel), new PropertyMetadata(Orientation.Horizontal, new PropertyChangedCallback(LinePanel.OnAnyPropertyChanged)));
        public static readonly DependencyProperty ReverseProperty = DependencyProperty.Register("Reverse", typeof(bool), typeof(LinePanel), new PropertyMetadata(false, new PropertyChangedCallback(LinePanel.OnAnyPropertyChanged)));

        // Methods
        public LinePanel()
        {
            NotifyCollectionChangedEventHandler handler = null;
            this._lineDefinitions = new ObservableCollection<LineDefinition>();
            if (handler == null)
            {
                handler = (s, e) => base.InvalidateMeasure();
            }
            this._lineDefinitions.CollectionChanged += handler;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            List<ChildLength> list = this.Pairs();
            double num = 0.0;
            foreach (ChildLength length in list)
            {
                UIElement child = length.Child;
                if ((child != null) && !length.Length.IsStar)
                {
                    if (this.Orientation == Orientation.Vertical)
                    {
                        num += child.DesiredSize.Height;
                    }
                    else
                    {
                        num += child.DesiredSize.Width;
                    }
                }
            }
            double num2 = 0.0;
            foreach (ChildLength length3 in list)
            {
                if (length3.Length.IsStar)
                {
                    num2 += length3.Length.Value;
                }
            }
            double num3 = Math.Max((double)0.0, (double)(((this.Orientation == Orientation.Vertical) ? finalSize.Height : finalSize.Width) - num));
            double y = 0.0;
            foreach (ChildLength length4 in list)
            {
                UIElement element2 = length4.Child;
                GridLength length5 = length4.Length;
                double height = 0.0;
                if (length5.IsStar)
                {
                    height = (num3 * length5.Value) / num2;
                }
                else if (element2 != null)
                {
                    if (this.Orientation == Orientation.Vertical)
                    {
                        height = Math.Min(element2.DesiredSize.Height, finalSize.Height - y);
                    }
                    else
                    {
                        height = Math.Min(element2.DesiredSize.Width, finalSize.Width - y);
                    }
                }
                if (element2 != null)
                {
                    if (this.Orientation == Orientation.Vertical)
                    {
                        element2.Arrange(new Rect(0.0, y, finalSize.Width, height));
                    }
                    else
                    {
                        element2.Arrange(new Rect(y, 0.0, height, finalSize.Height));
                    }
                    y += height;
                }
            }
            return finalSize;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            List<ChildLength> list = this.Pairs();
            double num = 0.0;
            double num2 = 0.0;
            foreach (ChildLength length in list)
            {
                UIElement child = length.Child;
                if ((child != null) && !length.Length.IsStar)
                {
                    if (this.Orientation == Orientation.Vertical)
                    {
                        child.Measure(new Size(availableSize.Width, double.PositiveInfinity));
                        num2 += child.DesiredSize.Height;
                        num = Math.Max(num, child.DesiredSize.Width);
                    }
                    else
                    {
                        child.Measure(new Size(double.PositiveInfinity, availableSize.Height));
                        num2 += child.DesiredSize.Width;
                        num = Math.Max(num, child.DesiredSize.Height);
                    }
                }
            }
            double num3 = 0.0;
            foreach (ChildLength length3 in list)
            {
                if (length3.Length.IsStar)
                {
                    num3 += length3.Length.Value;
                }
            }
            double num4 = Math.Max((double)0.0, (double)(((this.Orientation == Orientation.Vertical) ? availableSize.Height : availableSize.Width) - num2));
            double num5 = 0.0;
            foreach (ChildLength length4 in list)
            {
                UIElement element2 = length4.Child;
                if (element2 != null)
                {
                    GridLength length5 = length4.Length;
                    if (length5.IsStar)
                    {
                        double height = (num4 * length5.Value) / num3;
                        if (this.Orientation == Orientation.Vertical)
                        {
                            element2.Measure(new Size(availableSize.Width, height));
                            num5 += element2.DesiredSize.Height;
                            num = Math.Max(num, element2.DesiredSize.Width);
                        }
                        else
                        {
                            element2.Measure(new Size(height, availableSize.Height));
                            num5 += element2.DesiredSize.Width;
                            num = Math.Max(num, element2.DesiredSize.Height);
                        }
                    }
                }
            }
            if (this.Orientation == Orientation.Vertical)
            {
                return new Size(num, Math.Min(availableSize.Height, num2 + num5));
            }
            return new Size(Math.Min(availableSize.Width, num2 + num5), num);
        }

        private static void OnAnyPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ((LinePanel)sender).InvalidateMeasure();
        }

        private List<ChildLength> Pairs()
        {
            Trace.Assert(base.Children.Count <= this._lineDefinitions.Count);
            Trace.Assert(!this._lineDefinitions.Any<LineDefinition>(x => x.Length.IsAbsolute));
            List<ChildLength> list = new List<ChildLength>();
            int count = base.Children.Count;
            for (int i = 0; i < this._lineDefinitions.Count; i++)
            {
                ChildLength item = new ChildLength
                {
                    Child = (i < count) ? base.Children[i] : null,
                    Length = this._lineDefinitions[i].Length
                };
                list.Add(item);
            }
            if (this.Reverse)
            {
                list.Reverse();
            }
            return list;
        }

        // Properties
        public Collection<LineDefinition> LineDefinitions
        {
            get { return this._lineDefinitions; }
        }

        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        public bool Reverse
        {
            get { return (bool)GetValue(ReverseProperty); }
            set { SetValue(ReverseProperty, value); }
        }

        // Nested Types
        [StructLayout(LayoutKind.Sequential)]
        private struct ChildLength
        {
            public UIElement Child;
            public GridLength Length;
        }

        private class Trace
        {
            // Methods
            public static void Assert(bool b)
            {
                if (!b)
                {
                    "".ToString();
                }
            }
        }
    }

    public class LineDefinition
    {
        // Properties
        public GridLength Length { get; set; }
    }
}
